package Server;

import CommonOperationsClientServer.FilesOperations;
import CommonOperationsClientServer.OperationsRefactor;
import Users.User;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class StartCloseServer {

    private static int portServer = 9000;
    private static String serverConfigurationDirectory = "/ServerInfo";
    private static String serverConfigurationFile = "/serverConfiguration.txt";
    private static String serverDirectory = "Server";
    private static String serverLog = "/serverlog.txt";
    private static String usersFile = "/users.txt";
    private static String usersNoPrivilegedDirectory = "/Directorio Especial";
    private static boolean userActive = true;
    private static boolean serverActive = true;
    private static ServerSocket serverSocket;

    public static void main(String args[]) {
        setConfigurationServer();
        FilesOperationsServer.initializeServerFiles(serverDirectory, usersNoPrivilegedDirectory,
                serverConfigurationDirectory, usersFile, serverLog, serverConfigurationFile);
        FilesOperationsServer.updateServerConfiguration(serverConfigurationFile, serverLog);
        startServer();
    }

    public static void startServer() {
        Socket client = null;
        try {
            serverSocket = new ServerSocket(portServer);
            while (serverActive) {
                userActive = true;
                client = serverSocket.accept();
                RunServer connection = new RunServer(client);
                connection.start();
            }
        } catch (Exception e) {
        } finally {
            try {
                client.close();
            } catch (Exception e2) {
            }
        }
    }

    private static void closeServer() {
        serverActive = false;
    }

    private static void setConfigurationServer() {
        serverConfigurationDirectory = serverDirectory + serverConfigurationDirectory;
        serverConfigurationFile = serverConfigurationDirectory + serverConfigurationFile;
        usersFile = serverConfigurationDirectory + usersFile;
        usersNoPrivilegedDirectory = serverDirectory + usersNoPrivilegedDirectory;
        serverLog = FilesOperationsServer.getServerLogPath(serverConfigurationFile,
                serverConfigurationDirectory, serverLog);
    }

    public static int getPortServer() {
        return portServer;
    }

    public static String getServerDirectory() {
        return serverDirectory;
    }

    public static String getServerConfigurationDirectory() {
        return serverConfigurationDirectory;
    }

    public static String getServerConfigurationFile() {
        return serverConfigurationFile;
    }

    public static String getUsersFile() {
        return usersFile;
    }

    public static String getUsersNoPrivilegedDirectory() {
        return usersNoPrivilegedDirectory;
    }

    public static String getServerLog() {
        return serverLog;
    }

    public static void setServerLog(String newPath) {
        serverLog = newPath;
    }

    static class RunServer extends Thread {

        private Socket clientSocket;
        private BufferedReader input;
        private PrintWriter output;
        private User user;

        public RunServer(Socket clientSocket) {
            this.clientSocket = clientSocket;
        }

        public String getUser() {
            return user.getUserName();
        }

        public String getHostClient() {
            return clientSocket.getInetAddress().getHostAddress();
        }

        @Override
        public void run() {
            try {
                output = new PrintWriter(clientSocket.getOutputStream(), true);
                OperationsRefactor.outputMessage(output, "Bienvenido al servidor");
                input = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                while (userActive) {
                    String textoRecibido = input.readLine();
                    serverOption(textoRecibido);
                }
            } catch (Exception e) {
            } finally {
                try {
                    clientSocket.close();
                } catch (IOException e) {
                }
            }
        }

                //@Abraham Esto es bastante poco orientado a objetos;
        //mejor emplear el patrón comando
        public void serverOption(String option) {
            String[] clientEspecifications = option.split(";");
            switch (clientEspecifications[0]) {
                case "receiveuser":
                    String userConversion = clientEspecifications[1] + ";" + clientEspecifications[2] + ";"
                            + clientEspecifications[3];
                    user = UsersOperationsServer.receiveUser(User.stringToUser(userConversion), usersFile,
                            output);
                    FilesOperations.updateLog(StartCloseServer.getServerLog(), getUser(), getHostClient(),
                            "Receive user: " + user.getUserName());
                    break;
                case "uploadfile":
                    FilesOperationsServer.uploadFile(clientEspecifications[1], clientEspecifications[2],
                            user.getUserPrivileged(), usersNoPrivilegedDirectory, input, output);
                    FilesOperations.updateLog(StartCloseServer.getServerLog(), getUser(), getHostClient(),
                            "Upload file from client: " + clientEspecifications[1] + " to directory: "
                            + clientEspecifications[2]);
                    break;
                case "deletefile":
                    FilesOperationsServer.deleteFile(clientEspecifications[1], output);
                    FilesOperations.updateLog(StartCloseServer.getServerLog(), getUser(), getHostClient(),
                            "Delete file: " + clientEspecifications[1]);
                    break;
                case "downloadfile":
                    FilesOperationsServer.downloadFile(clientEspecifications[1], usersNoPrivilegedDirectory,
                            user.getUserPrivileged(), input, output);
                    FilesOperations.updateLog(StartCloseServer.getServerLog(), getUser(), getHostClient(),
                            "Send file to client: " + clientEspecifications[1]);
                    break;
                case "createfolder":
                    FilesOperationsServer.createFolder(clientEspecifications[1], clientEspecifications[2],
                            output);
                    FilesOperations.updateLog(StartCloseServer.getServerLog(), getUser(), getHostClient(),
                            "Create folder: " + clientEspecifications[2] + " in: "
                            + clientEspecifications[1]);
                    break;
                case "deletefolder":
                    FilesOperationsServer.deleteFolder(clientEspecifications[1], output, false);
                    FilesOperations.updateLog(StartCloseServer.getServerLog(), getUser(), getHostClient(),
                            "Delete folder: " + clientEspecifications[1]);
                    break;
                case "createuser":
                    String userData = clientEspecifications[1] + ";" + clientEspecifications[2] + ";"
                            + clientEspecifications[3];
                    UsersOperationsServer.createNewUser(User.stringToUser(userData), usersFile, input,
                            output, false);
                    FilesOperations.updateLog(StartCloseServer.getServerLog(), getUser(), getHostClient(),
                            "Create new user: " + clientEspecifications[1]);
                    break;
                case "deleteuser":
                    output.println(UsersOperationsServer.listOfUsers(usersFile));
                    output.flush();
                    UsersOperationsServer.deleteUser(usersFile, input, output);
                    FilesOperations.updateLog(StartCloseServer.getServerLog(), getUser(), getHostClient(),
                            "Delete user");
                    break;
                case "listdirectoryserver":
                    FilesOperationsServer.directoryFiles(clientEspecifications[1], output);
                    break;
                case "filepermissions":
                    FilesOperationsServer.sendInfoFromLocalFile(clientEspecifications[1], output);
                    FilesOperations.updateLog(StartCloseServer.getServerLog(), getUser(), getHostClient(),
                            "File permissions of: " + clientEspecifications[1]);
                    break;
                case "getserverconfiguration":
                    FilesOperationsServer.sendServerConfiguration(output, serverSocket);
                    FilesOperations.updateLog(StartCloseServer.getServerLog(), getUser(), getHostClient(),
                            "Get server configuration");
                    break;
                case "modifyserverlog":
                    FilesOperationsServer.moveServerLog(serverConfigurationFile,
                            clientEspecifications[1].toLowerCase(), output);
                    FilesOperations.updateLog(StartCloseServer.getServerLog(), getUser(), getHostClient(),
                            "Move server log to: " + clientEspecifications[1]);
                    break;
                case "executecommand":
                    UsersOperationsServer.receiveCommand(clientEspecifications[1], output);
                    FilesOperations.updateLog(StartCloseServer.getServerLog(), getUser(), getHostClient(),
                            "Execute command: " + clientEspecifications[1]);
                    break;
                case "disconnect":
                    OperationsRefactor.outputMessage(output, "Good Bye!!!!");
                    FilesOperations.updateLog(StartCloseServer.getServerLog(), getUser(), getHostClient(),
                            clientEspecifications[0]);
                    userActive = false;
                    break;
                case "stopserver":
                    FilesOperations.updateLog(StartCloseServer.getServerLog(), getUser(), getHostClient(),
                            clientEspecifications[0]);
                    closeServer();
                    System.exit(0);
                    break;
            }
        }
    }
}
